Skip to content

refactor(uts): make :uts a shared test-infra module, move UTS suites to owning modules; objects spec-conformance - #1229

Merged
sacOO7 merged 10 commits into
fix/liveobjects-objects-audit-op-handlingfrom
refactor/uts-objects-unit-into-liveobjects
Aug 27, 2026
Merged

refactor(uts): make :uts a shared test-infra module, move UTS suites to owning modules; objects spec-conformance#1229
sacOO7 merged 10 commits into
fix/liveobjects-objects-audit-op-handlingfrom
refactor/uts-objects-unit-into-liveobjects

Conversation

@sacOO7

@sacOO7 sacOO7 commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to the cross-SDK objects audit, in two stages that landed on this branch (the second — #1231 — was reviewed separately and merged here). Net effect, four related changes:

  1. :uts becomes a shared test-infra module — the UTS infra (mock WebSocket/HTTP transports, FakeClock, SandboxApp, proxy control) is now :uts's main source set, and the module api-exports the UTS test-writing toolkit (JUnit 5 BOM/aggregator/params, the kotlin-test Jupiter binding, coroutines). Consumers need exactly one line: testImplementation(project(":uts")). (An intermediate testFixtures stage existed during development and was superseded on this same branch — the net diff contains no java-test-fixtures.)
  2. UTS suites move to the modules that own the code they test — objects unit/integration/proxy → :liveobjects (…/uts/{unit,integration,proxy}, with the unit tier expanded: new InternalLiveCounter, InternalLiveMap, ObjectId, ObjectsPool, ParentReferences suites); realtime unit/integration/proxy → :java at lib/src/test/kotlin/io/ably/lib/uts/… (new Jupiter-only :java:runUtsUnitTests / :java:runUtsIntegrationTests tasks — the 64 legacy JUnit4 tests and their suite tasks are untouched). :uts keeps three permanent, deep tier smoke tests (modeled on ably-cocoa#2223) that serve as infra acceptance and the uts/README.md teaching examples.
  3. Production spec-conformance (liveobjects/src/main) — op-path returns ObjectUpdate, plus two root-object safeguards.
  4. Mock-infra contract correctness — review-driven fixes verified against the UTS docs’ mock contracts (see “Mock contract fixes” below).

Based on fix/liveobjects-objects-audit-op-handling (not main).

Related spec / cross-SDK context

Changes

1. :uts = shared test-infra module

  • 16 infra files live at uts/src/main/kotlin/io/ably/lib/uts/infra/ (packages unchanged — zero import churn for consumers).
  • :uts is java-library + kotlin.jvm; deps: api(:java), api(:network-client-core), ktor as implementation (never leaks), plus the api-exported test toolkit. Declares Java-8 outgoing variants so :java (targetCompatibility 1.8) can consume it.
  • Invariant (documented in uts/build.gradle.kts): :uts’s main configurations never depend on :liveobjects:liveobjects test → :uts main → :java stays acyclic, and the old testRuntimeOnly(:liveobjects) edge is gone entirely (the objects tests now live inside :liveobjects).

2. UTS suites in their owning modules

  • Objectsliveobjects/src/test/…/uts/{unit,integration,proxy} (packages io.ably.lib.liveobjects.uts.*). :liveobjects adopts the JUnit Platform (kotlin("test-junit5") pinned; vintage engine runs its own legacy JUnit4 tests). runLiveObjectsUnitTests filters both …unit.* and …uts.unit.*; runLiveObjectsIntegrationTests additionally covers …uts.{integration,proxy}.*.
  • Realtimelib/src/test/kotlin/io/ably/lib/uts/… (:java; packages unchanged). :java gains the Kotlin plugin for tests only — a guardrail strips the auto-added kotlin-stdlib from all main-artifact scopes (verified: POM and jar contain zero Kotlin; the leak source is the plugin, not the :uts test dependency).
  • :uts smoke testsUnitInfraSmokeTest (mock transport lifecycle incl. FakeClock cascades), IntegrationInfraSmokeTest (sandbox round-trip, protocol-parameterized), ProxyInfraSmokeTest (proxy session, declarative + imperative fault injection). Not spec-derived (no @UTS markers).
  • CI re-pointed in the same change (no silent-green): check.yml runs :java:runUtsUnitTests + :uts:runUtsUnitTests alongside the existing tasks; integration-test.yml’s check-uts runs :java:runUtsIntegrationTests + :uts:runUtsIntegrationTests; check-liveobjects picks up the moved objects tiers via the extended filter.
  • Deviations live with their tests: lib/src/test/kotlin/io/ably/lib/uts/deviations.md (realtime/rest) and liveobjects/…/uts/deviations.md (objects, all tiers).
  • The uts-to-kotlin skill’s mapping is simplified to one repo-root-relative path per tier; the resolver reports the owning Gradle module.

3. Production spec-conformance (liveobjects/src/main)

  • Op-path returns ObjectUpdate instead of Boolean (RTLC9g/RTLM7f). The RTO9a2a4 on-ack serial gate now uses !update.noOp, matching the UTS model where result == true ⟺ !update.noop.
  • Root object excluded from GC (RTO10c1b1).
  • Root object rejects tombstone attempts (RTLO4e10).
  • Both safeguards covered by new tests (LiveObjectTombstoneTest).

4. Mock contract fixes (review-driven, verified against the UTS docs)

  • FakeClock.advance runs due work to quiescence (cascades and timers created mid-advance fire within the same advance — spec Fixes in HttpScheduler.AsyncRequest #518’s Guarantee); timer state hardened against SDK-thread races. The waitOn advisory seam is documented in uts/README.md §6.4, and the smoke test owns reconnect attempts deterministically (the CI-flake fix).
  • Transport cancel() delivers listener.onClose (per the SDK’s own WebSocketClient contract); respondWith honors the headers param and derives the body content-type case-insensitively; SandboxApp.create() checks HTTP status before parsing; teardown rethrows CancellationException; assorted @Volatile/listener-cleanup hygiene.
  • One test-race hardening: RTO24b1 awaits its seed’s observable effect before subscribing (async-delivery race on slow runners), matching the file’s established pattern.

Verification

  • Unit: :java:runUnitTests (legacy, count unchanged) · :java:runUtsUnitTests 6/0 · :uts:runUtsUnitTests 3/0 · :liveobjects:runLiveObjectsUnitTests 389/0.
  • Integration (sandbox + uts-proxy, from the new homes): :java:runUtsIntegrationTests 5/0 · :uts:runUtsIntegrationTests 4/0 · :liveobjects:runLiveObjectsIntegrationTests 29/0.
  • Publication isolation: :java POM/jar contain zero org.jetbrains.kotlin entries; jar file list byte-identical to pre-change.
  • @UTS test-ID parity across all moves: identical sets before/after (zero coverage loss).
  • checkWithCodenarc checkstyleMain checkstyleTest — green.

Follow-up TODOs

Most of the original deferred list has since landed on this branch; what remains:

  • Extract shared infra so other modules consume it without testFixtures — done, via promotion to :uts’s main source set (chosen over a new :test-support module: zero import churn, no settings change; rationale in FUTURE_WORK_UTS_INFRA.md).
  • Kotlin test source set in :java with the kotlin-stdlib guardrail — done (guardrail verified against POM/jar/runtimeClasspath).
  • Simplify uts-package-mapping.json to one full path per tier — done (resolver also reports the owning module).
  • Decide Chat SDK consumption: in-repo module (testImplementation(project(":uts"))) vs. separate-repo publish/version. :uts is publish-ready but publishing stays an explicit opt-in decision.
  • File the spec-hygiene issue for the existing spec tests that assert timer-absence before ADVANCE_TIME (tracked alongside uts: define normative fake-time semantics (ADVANCE_TIME guarantee, hard-gate vs advisory, authoring rule) specification#518).

Notes for reviewers

Read as four changes, not move noise: the op-path return and root-object safeguards are behavioural (§3); the mock contract fixes (§4) change test-infra behaviour; §1–§2 are structure. The 16 infra files and the realtime tests are pure renames (R100); the four moved objects tests changed only their package lines (plus one forced one-token smart-cast fix in AuthReauthTest, explained inline). uts/README.md is rewritten around the new layout and its walkthroughs teach from the smoke tests; FUTURE_WORK_UTS_INFRA.md is the decision record for how the final design was reached.

…uite into :liveobjects

Three related changes from the cross-SDK objects audit follow-up:

1. Shared UTS test infra (mock transport, FakeClock, SandboxApp, proxy control)
   moves from :uts's src/test to its src/testFixtures variant, so other modules
   can consume it via testFixtures(project(":uts")). Acyclicity invariant
   documented: :liveobjects test -> :uts testFixtures -> :java, with :uts test ->
   :liveobjects kept runtime-only.

2. The objects UTS unit suite moves out of :uts into the :liveobjects module's own
   test source set (package io.ably.lib.liveobjects.uts.unit) so the internal-graph
   specs can reach `internal` members directly. Coverage expands: adds
   InternalLiveCounter/Map, ObjectId, ObjectsPool and ParentReferences suites.
   runLiveObjectsUnitTests now covers both .unit.* and .uts.unit.*.

3. Spec-conformance in production source:
   - op-path applyObject/applyOperation now returns the ObjectUpdate instead of a
     Boolean (RTLC9g/RTLM7f); the RTO9a2a4 on-ack gate uses !update.noOp.
   - root object is excluded from GC (RTO10c1b1) and rejects tombstone attempts
     (RTLO4e10); both covered by new tests.

Deviations recorded in liveobjects/.../uts/deviations.md. Unit suites and the CI
static-analysis gate are green.
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 34 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f198855e-e2ae-47ac-ad34-2847ed813489

📥 Commits

Reviewing files that changed from the base of the PR and between ee2e1f1 and e20bc69.

📒 Files selected for processing (86)
  • .claude/skills/uts-to-kotlin/SKILL.md
  • .claude/skills/uts-to-kotlin/references/objects-mapping.md
  • .claude/skills/uts-to-kotlin/scripts/audit_translation.py
  • .claude/skills/uts-to-kotlin/scripts/resolve_uts.py
  • .claude/skills/uts-to-kotlin/uts-package-mapping.json
  • .github/workflows/check.yml
  • .github/workflows/integration-test.yml
  • FUTURE_WORK_UTS_INFRA.md
  • gradle/libs.versions.toml
  • java/build.gradle.kts
  • lib/src/test/kotlin/io/ably/lib/uts/deviations.md
  • lib/src/test/kotlin/io/ably/lib/uts/integration/proxy/realtime/AuthReauthTest.kt
  • lib/src/test/kotlin/io/ably/lib/uts/integration/standard/realtime/ChannelHistoryTest.kt
  • lib/src/test/kotlin/io/ably/lib/uts/integration/standard/realtime/TokenRequestTest.kt
  • lib/src/test/kotlin/io/ably/lib/uts/unit/realtime/ConnectionRecoveryTest.kt
  • liveobjects/build.gradle.kts
  • liveobjects/src/main/kotlin/io/ably/lib/liveobjects/DefaultRealtimeObject.kt
  • liveobjects/src/main/kotlin/io/ably/lib/liveobjects/ObjectsManager.kt
  • liveobjects/src/main/kotlin/io/ably/lib/liveobjects/ObjectsPool.kt
  • liveobjects/src/main/kotlin/io/ably/lib/liveobjects/ObjectsState.kt
  • liveobjects/src/main/kotlin/io/ably/lib/liveobjects/ObjectsSyncTracker.kt
  • liveobjects/src/main/kotlin/io/ably/lib/liveobjects/message/WireObjectMessage.kt
  • liveobjects/src/main/kotlin/io/ably/lib/liveobjects/value/BaseRealtimeLiveObject.kt
  • liveobjects/src/main/kotlin/io/ably/lib/liveobjects/value/livecounter/InternalLiveCounter.kt
  • liveobjects/src/main/kotlin/io/ably/lib/liveobjects/value/livecounter/LiveCounterManager.kt
  • liveobjects/src/main/kotlin/io/ably/lib/liveobjects/value/livemap/InternalLiveMap.kt
  • liveobjects/src/main/kotlin/io/ably/lib/liveobjects/value/livemap/LiveMapManager.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/integration/setup/Sandbox.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/unit/DefaultRealtimeObjectChannelStateTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/unit/LiveObjectTombstoneTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/unit/ObjectMessageSizeTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/README.md
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/deviations.md
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/integration/Helpers.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/integration/ObjectsLifecycleTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/integration/ObjectsSyncTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/proxy/ObjectsFaultsTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/Helpers.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/InstanceTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/InternalLiveCounterApiTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/InternalLiveCounterTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/InternalLiveMapApiTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/InternalLiveMapTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/LiveObjectSubscribeTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/ObjectIdTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/ObjectsPoolTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/ParentReferencesTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/PathObjectMutationsTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/PathObjectSubscribeTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/PathObjectTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/PublicObjectMessageTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/RealtimeObjectTest.kt
  • liveobjects/src/test/kotlin/io/ably/lib/liveobjects/uts/unit/ValueTypesTest.kt
  • uts/README.md
  • uts/build.gradle.kts
  • uts/src/main/kotlin/io/ably/lib/uts/infra/Utils.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/integration/SandboxApp.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/integration/proxy/ProxyManager.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/integration/proxy/ProxySession.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/unit/ClientFactories.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/unit/DefaultPendingConnection.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/unit/DefaultPendingRequest.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/unit/FakeClock.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/unit/MockEvent.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/unit/MockHttpClient.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/unit/MockHttpEngine.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/unit/MockWebSocket.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/unit/MockWebSocketEngineFactory.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/unit/PendingConnection.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/unit/PendingRequest.kt
  • uts/src/main/kotlin/io/ably/lib/uts/infra/unit/Utils.kt
  • uts/src/test/kotlin/io/ably/lib/uts/deviations.md
  • uts/src/test/kotlin/io/ably/lib/uts/integration/proxy/ProxyInfraSmokeTest.kt
  • uts/src/test/kotlin/io/ably/lib/uts/integration/standard/IntegrationInfraSmokeTest.kt
  • uts/src/test/kotlin/io/ably/lib/uts/private_deviations.md
  • uts/src/test/kotlin/io/ably/lib/uts/unit/UnitInfraSmokeTest.kt
  • uts/src/test/kotlin/io/ably/lib/uts/unit/liveobjects/Helpers.kt
  • uts/src/test/kotlin/io/ably/lib/uts/unit/liveobjects/InstanceTest.kt
  • uts/src/test/kotlin/io/ably/lib/uts/unit/liveobjects/InternalLiveCounterApiTest.kt
  • uts/src/test/kotlin/io/ably/lib/uts/unit/liveobjects/InternalLiveMapApiTest.kt
  • uts/src/test/kotlin/io/ably/lib/uts/unit/liveobjects/LiveObjectSubscribeTest.kt
  • uts/src/test/kotlin/io/ably/lib/uts/unit/liveobjects/PathObjectMutationsTest.kt
  • uts/src/test/kotlin/io/ably/lib/uts/unit/liveobjects/PathObjectTest.kt
  • uts/src/test/kotlin/io/ably/lib/uts/unit/liveobjects/PublicObjectMessageTest.kt
  • uts/src/test/kotlin/io/ably/lib/uts/unit/liveobjects/RealtimeObjectTest.kt
  • uts/src/test/kotlin/io/ably/lib/uts/unit/liveobjects/ValueTypesTest.kt

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions
github-actions Bot temporarily deployed to staging/pull/1229/features July 30, 2026 11:40 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/1229/javadoc July 30, 2026 11:42 Inactive
The channel-state handler routes the ATTACHED transition to the sync lifecycle
(RTO4) and all other states per RTO27, so add a method KDoc tagging both spec
points, inline RTO27a/RTO27a1/RTO27a2 tags on the DETACHED/FAILED clear (with
SUSPENDED excluded and retained per RTO27b), and an RTO27b tag on the else branch.
Comment/doc only; no behaviour change. Mirrors the ably-js actOnChannelState tags.
@github-actions
github-actions Bot temporarily deployed to staging/pull/1229/features July 31, 2026 09:15 Inactive
@github-actions
github-actions Bot temporarily deployed to staging/pull/1229/javadoc July 31, 2026 09:16 Inactive
…nd add their UTS unit tests

- RTO23c1: a get() parked waiting for objects sync now fails when the channel
  enters DETACHED/SUSPENDED/FAILED — ensureSynced routes through the shared
  pendingSyncWaiters, each waiter carrying a caller-specific failure
  description (the object could not be retrieved vs RTO20e1's operation could
  not be applied locally), built into the 92008/400/cause error at the
  failure site.
- RTO5a6: a malformed OBJECT_SYNC channelSerial (no ':' separator) is
  normalized to null so it takes the same branch as an absent serial
  (RTO5a5), with a warning logged.
- Add the five UTS unit tests derived from the new spec cases (3x RTO23c1
  per channel state, RTO5a5, RTO5a6).
- Annotate the implementation sites of the newly specified points (RTO20d4,
  RTLC14c, RTLM22c).

Spec changes: ably/specification#514
Companion ably-js fix: ably/ably-js#2284
Port the seven no-op-package UTS cases: RTLC14c/RTLM22c (zero-delta/empty
diffs are no-op updates, never delivered), RTO20d4 (empty synthetic list
skips the RTO20e sync wait), the RTLO5 tombstone-of-zero/empty-object cases
and the RTLO4b4c3c zero-valued-counter teardown case (covering
BaseRealtimeLiveObject.tombstone()'s NoOp-synthesis branch for the first
time), and RTO4b2a (reset of an already-empty root emits no update; verified
with a second-pool liveness control via a backward-compatible optional
target parameter on the ObjectsPoolTest processAttached helper).

Production already conforms at every site; test-only change.

Spec changes: ably/specification#515
Companion ably-js fix: ably/ably-js#2288
…(OMP4a1)

Message-size accounting matches Ably's published per-field rule: every plain string field and map key is measured as its UTF-8 byte length, while extras keeps the documented "string length of its JSON representation" (UTF-16 code units).

Sites changed:
- WireObjectMessage.kt: WireObjectsMap.size (OMP4a1) key measurement it.key.length -> it.key.byteSize, so map-state entry keys now match the MapCreate/MapSet/MapRemove operation keys; fixed a duplicated-// comment typo; corrected the WireObjectData json branch comment from OD3e to OD3g; extras keeps gson.toJson(it).length (UTF-16) now with an explanatory comment.

Tests: +1 non-ASCII test testObjectMapStateEntryKeyUnicodeSizeIsUtf8 (OMP4a1).

Spec: ably/specification#516
sacOO7 added 5 commits August 24, 2026 19:27
…to their owning modules

:uts's shared test infrastructure is promoted from the java-test-fixtures
variant to a normal main source set, and the spec-derived UTS suites move
to the modules that own the code they test:

- Infra: uts/src/testFixtures -> uts/src/main (16 pure renames, packages
  io.ably.lib.uts.infra.* unchanged). :uts is now java-library + kotlin.jvm
  and api-exports the UTS test toolkit (junit-bom/jupiter/params,
  kotlin-test-junit5, coroutines) so consumers need only
  testImplementation(project(":uts")). ktor stays implementation.
- Realtime tiers -> :java at lib/src/test/kotlin (packages unchanged; new
  :java:runUtsUnitTests / :java:runUtsIntegrationTests Jupiter tasks; the
  64 legacy JUnit4 tests and suite tasks are untouched; kotlin-stdlib is
  kept out of the published artifact - POM/jar verified clean).
- Objects integration/proxy tiers -> :liveobjects at .../uts/{integration,
  proxy}, joining the existing uts/unit; :liveobjects adopts the JUnit
  Platform (vintage engine runs its own legacy JUnit4 tests).
- :uts keeps three permanent, deep tier smoke tests (unit/integration/
  proxy) modeled on ably-cocoa#2223 - infra acceptance + the teaching
  examples uts/README.md now walks through.
- uts-to-kotlin skill: mapping simplified to one repo-root-relative path
  per tier; resolver emits the owning module; docs re-pointed.
- CI: check.yml and integration-test.yml re-pointed so every moved suite
  keeps exactly one CI home (no silent-green).

Verified: 533 tests green across all tiers (98 java unit, 6+2 UTS unit,
389 objects unit, 5+4+29 integration/proxy); @uts test-id parity proven
(27 ids, zero loss); checkstyle/codenarc clean.
…iescence FakeClock

Fixes the CI-red UnitInfraSmokeTest race and lands the review/spec-alignment
round on the shared UTS infra:

- Root cause of the CI flake: FakeClock.waitOn performs a real timed wait, so
  the disconnected-retry fires on wall-clock regardless of advance() — the
  "no attempt before advance" assertion was unassertable. The smoke test now
  owns attempt #2 via the buffered awaitConnectionAttempt() (32/32 green incl.
  CPU-saturation runs) and README §6.4/§9 teach the true semantics.
- FakeClock: advance() now runs due work to quiescence (cascades and timers
  created mid-advance fire within the same advance — the spec's Fake-time
  semantics Guarantee); timers/pending hardened against SDK-thread races.
  The waitOn advisory seam is unchanged. New cascade smoke test covers it.
- Mock contract fixes from review triage (verified against the UTS docs):
  transport cancel() now delivers listener.onClose; respondWith honors the
  headers param and JSON-serializes non-String bodies; SandboxApp checks HTTP
  status before parsing; delivery executor shutdown; @volatile channel fields;
  await helpers unregister listeners on success; AtomicReference for the
  cross-thread query-params capture.
- Docs: uts/README rewritten claims verified against sources; stale
  "reflection" wording fixed in the skill's objects-mapping notes.
- DefaultPendingConnection: submit -> execute so a delivery exception
  reaches the thread's uncaught handler instead of a discarded Future.
- DefaultPendingRequest: derive the body content-type from a
  case-insensitive Content-Type header lookup (default application/json)
  so caller-supplied headers are honored without conflicting metadata.
- MockWebSocket: null activeListener on client-initiated close, matching
  every other close path; post-close sends now fail fast.
- SandboxApp: delete() rethrows CancellationException (cooperative
  cancellation preserved); other errors remain best-effort-ignored per
  the documented teardown contract.
…ribing

The test seeded a second path (alias) via send_to_client and subscribed
immediately; the SDK applies inbound messages asynchronously, so on a slow
runner the seed's MAP_SET dispatch raced the subscription and the alias
listener saw two events (seed + increment) instead of one. Await the seed's
observable effect first — the same hardening the depth tests in this file
already use, per the documented async-delivery caveat in the skill's
objects-mapping notes.
…nd-suite-redistribution

refactor(uts): make :uts a shared test-infra module and move UTS suites to their owning modules
@sacOO7 sacOO7 changed the title refactor(uts): share test infra via testFixtures, move objects unit suite into :liveobjects refactor(uts): make :uts a shared test-infra module, move UTS suites to owning modules; objects spec-conformance Aug 27, 2026
@sacOO7
sacOO7 marked this pull request as ready for review August 27, 2026 11:30
@sacOO7
sacOO7 merged commit 9afa940 into fix/liveobjects-objects-audit-op-handling Aug 27, 2026
15 checks passed
@sacOO7
sacOO7 deleted the refactor/uts-objects-unit-into-liveobjects branch August 27, 2026 11:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant